home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / sp / part02 < prev    next >
Encoding:
Internet Message Format  |  1987-02-19  |  17.8 KB

  1. Subject:  v08i077:  Soundex spelling checker, Part02/02
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: Barry Brachman <brachman@cs.ubc.cdn>
  6. Mod.sources: Volume 8, Issue 77
  7. Archive-name: sp/Part02
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line,
  11. # then unpack it by saving it in a file and typing "sh file".
  12. # If all goes well, you will see the message "End of archive 2 (of 2)."
  13. # Contents:  sp.9 sp.c sp.h sp.ml
  14. PATH=/bin:/usr/bin:/usr/ucb; export PATH
  15. echo shar: extracting "'sp.9'" '(1112 characters)'
  16. if test -f 'sp.9' ; then 
  17.   echo shar: will not over-write existing file "'sp.9'"
  18. else
  19. sed 's/^X//' >sp.9 <<'@//E*O*F sp.9//'
  20. X.TH SP 9-EMACS "8-Aug-1985"
  21. X.UC
  22. X.SH NAME
  23. Xsp, sp-from-buffer \- give possible spellings
  24. X.br
  25. Xget-next-word \- return word at cursor
  26. X.SH SYNOPSIS
  27. X.B (sp)
  28. X.br
  29. X.B (sp-from-buffer)
  30. X.br
  31. X.B (get-next-word)
  32. X.SH DESCRIPTION
  33. X.I Sp
  34. Xprompts for a word and then invokes the
  35. X.B sp
  36. Xprogram with the word as an argument.
  37. XThe output of the
  38. X.B sp
  39. Xprogram, a list of words, is placed in a buffer called "sp".
  40. XIf the word is found, then the cursor is positioned at the word.
  41. XIf the word isn't found, the cursor is left at the start of the buffer.
  42. XIn either case the mode line of the buffer indicates whether the word
  43. Xwas found.
  44. X.sp 2
  45. X.B Sp-from-buffer
  46. Xis the same as
  47. X.B sp
  48. Xexcept that the user is not prompted for the word; the word under or
  49. Ximmediately to the left of the cursor is used.
  50. X.sp 2
  51. X.B Get-next-word
  52. Xreturns the word the cursor is pointing at or the word immediately
  53. Xto the left of the cursor if it is between words.
  54. X.SH BUFFERS USED
  55. Xsp \- result
  56. X.SH FILES
  57. X/usr/local/lib/emacs/sp.ml
  58. X.br
  59. X/usr/local/sp
  60. X.SH SEE ALSO
  61. X.B sp(1-LOCAL)
  62. X.SH AUTHOR
  63. XBarry Brachman
  64. X.br
  65. XDept. of Computer Science
  66. X.br
  67. XUniversity of British Columbia
  68. @//E*O*F sp.9//
  69. if test 1112 -ne "`wc -c <'sp.9'`"; then
  70.     echo shar: error transmitting "'sp.9'" '(should have been 1112 characters)'
  71. fi
  72. fi # end of overwriting check
  73. echo shar: extracting "'sp.c'" '(9128 characters)'
  74. if test -f 'sp.c' ; then 
  75.   echo shar: will not over-write existing file "'sp.c'"
  76. else
  77. sed 's/^X//' >sp.c <<'@//E*O*F sp.c//'
  78. X/* vi: set tabstop=4 : */
  79. X
  80. X/*
  81. X * Version 1.3 December 1986
  82. X *
  83. X * sp - spell word
  84. X *
  85. X * Usage:    sp [-f dictionary-list] [-eavc] [word ...]
  86. X *
  87. X * Compute the Soundex code for each word on the command line
  88. X * (or each word on the standard input) and compare against a
  89. X * dictionary
  90. X *
  91. X * The soundex dictionary list may be specified on the command line
  92. X * The environment variable SPPATH may be set to a list of colon
  93. X * separated pathnames of soundex dictionaries.
  94. X * If a command line dictionary-list (a colon separated list of pathnames) is
  95. X * given in addition to the SPPATH variable, all dictionaries are used.
  96. X *
  97. X * To reduce the size of the word list, certain heuristics are used:
  98. X * the -a option causes all words matched to be printed
  99. X * The output is alphabetically sorted and indicators are printed
  100. X * beside each word:
  101. X *    X   == exact match
  102. X *    !   == close match
  103. X *    *   == near match
  104. X * ' '  == matched
  105. X *
  106. X * Note that the maximum number of colliding words is MAXCOUNT due to the
  107. X * data structure used.
  108. X *
  109. X * Permission is given to copy or distribute this program provided you
  110. X * do not remove this header or make money off of the program.
  111. X *
  112. X * Please send comments and suggestions to:
  113. X *
  114. X * Barry Brachman
  115. X * Dept. of Computer Science
  116. X * Univ. of British Columbia
  117. X * Vancouver, B.C. V6T 1W5
  118. X *
  119. X * .. {ihnp4!alberta, uw-beaver}!ubc-vision!ubc-cs!brachman
  120. X * brachman@cs.ubc.cdn
  121. X * brachman%ubc.csnet@csnet-relay.arpa
  122. X * brachman@ubc.csnet
  123. X */
  124. X
  125. X#include <sys/types.h>
  126. X#include <sys/file.h>
  127. X#include <ctype.h>
  128. X#include <stdio.h>
  129. X
  130. X#ifdef NEWDBM
  131. X#include <ndbm.h>
  132. X#else !NEWDBM
  133. X#include <dbm.h>
  134. X#endif NEWDBM
  135. X
  136. X#include "sp.h"
  137. X
  138. X#define streq(X, Y)    (!strcmp(X, Y))
  139. X#define range(S)    ((strlen(S) + 4) / 5)
  140. X
  141. X#define USAGE        "Usage: sp [-f dictionary-list] [-eavc] [word ...]"
  142. X
  143. Xchar word[MAXWORDLEN + 2];
  144. X
  145. Xdatum FETCH();
  146. X
  147. Xchar *fileptr[MAXDICT + 1];    /* Up to MAXDICT dictionaries + sentinel */
  148. Xint dict_ptr = 0;
  149. X
  150. Xchar *wordptr[MAXWORDS], *wordlistptr;
  151. Xchar wordlist[WORDSPACE];
  152. Xint nmatched;
  153. X
  154. X/*
  155. X * Soundex codes
  156. X * The program depends upon the numbers zero through six being used
  157. X * but this can easily be changed
  158. X */
  159. Xchar soundex_code_map[26] = {
  160. X/***     A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P    ***/ 
  161. X         0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, 1,
  162. X
  163. X/***     Q  R  S  T  U  V  W  X  Y  Z            ***/
  164. X         2, 6, 2, 3, 0, 1, 0, 2, 0, 2
  165. X};
  166. X
  167. Xint aflag, cflag, eflag, vflag;
  168. X
  169. Xmain(argc, argv)
  170. Xint argc;
  171. Xchar **argv;
  172. X{
  173. X    register int fflag, i;
  174. X    register char *p;
  175. X    char *getenv();
  176. X
  177. X    argc--; argv++;
  178. X    fileptr[0] = (char *) NULL;
  179. X    while (argc > 0 && argv[0][0] == '-') {
  180. X        fflag = 0;        /* to break out of following loop... */
  181. X        for (i = 1; argv[0][i] != '\0' && fflag == 0; i++) {
  182. X            switch (argv[0][i]) {
  183. X            case 'a':
  184. X                aflag = 1;
  185. X                break;
  186. X            case 'c':
  187. X                cflag = 1;
  188. X                break;
  189. X            case 'e':
  190. X                eflag = 1;
  191. X                break;
  192. X            case 'f':
  193. X                if (argc == 1) {
  194. X                    fprintf(stderr, "%s\n", USAGE);
  195. X                    exit(1);
  196. X                }
  197. X                mkfilelist(argv[1]);
  198. X                argc--;
  199. X                argv++;
  200. X                fflag = 1;        /* break out of loop */
  201. X                break;
  202. X            case 'v':
  203. X                vflag = 1;
  204. X                break;
  205. X            default:
  206. X                fprintf(stderr, "%s\n", USAGE);
  207. X                exit(1);
  208. X            }
  209. X        }
  210. X        argc--, argv++;
  211. X    }
  212. X
  213. X    if ((p = getenv("SPPATH")) != (char *) NULL)
  214. X        mkfilelist(p);
  215. X    if (fileptr[0] == (char *) NULL)
  216. X        mkfilelist(DEFAULT_SPPATH);
  217. X    if (vflag) {
  218. X        printf("Using dictionaries:\n");
  219. X        for (i = 0; fileptr[i] != (char *) NULL; i++)
  220. X            if (strlen(fileptr[i]) > 0)
  221. X                printf("\t%s\n", fileptr[i]);
  222. X    }
  223. X    if (argc) {
  224. X        for (i = 0; i < argc; i++) {
  225. X            if (!eflag)
  226. X                printf("%s:\n", argv[i]);
  227. X            apply(argv[i]);
  228. X            if (!eflag)
  229. X                printf("\n");
  230. X        }
  231. X    }
  232. X    else {
  233. X        int ch, len;
  234. X
  235. X        while (1) {
  236. X            printf("Word? ");
  237. X            if (fgets(word, sizeof(word), stdin) == (char *) NULL) {
  238. X                printf("\n");
  239. X                break;
  240. X            }
  241. X            len = strlen(word);
  242. X            if (word[len - 1] != '\n') {
  243. X                fprintf(stderr, "sp: Word too long: %s", word);
  244. X                while ((ch = getchar()) != '\n')    /* flush rest of line */
  245. X                    putc(ch, stderr);
  246. X                putc('\n', stderr);
  247. X                continue;
  248. X            }
  249. X            word[--len] = '\0';
  250. X            if (len > MAXWORDLEN) {
  251. X                fprintf(stderr, "sp: Word too long: %s\n", word);
  252. X                continue;
  253. X            }
  254. X
  255. X            apply(word);
  256. X            if (!eflag)
  257. X                printf("\n");
  258. X        }
  259. X    }
  260. X}
  261. X
  262. X/*
  263. X * Apply the Soundex search for a word to each dictionary in turn
  264. X * Note that 'DBMINIT' opens both the '.dir' and the '.pag' files
  265. X * and we must close them to avoid running out of file descriptors
  266. X *
  267. X * This routine gets called each time a word is looked up and therefore
  268. X * the dbm files may be repeatedly opened and closed.  Since the vast majority
  269. X * of the time this program is invoked for just a single word it doesn't seem
  270. X * worthwhile to do the right thing by saving file descriptors/DBM pointers.
  271. X * There probably won't be more than two dictionaries in use anyway.
  272. X */
  273. Xapply(word)
  274. Xchar *word;
  275. X{
  276. X    register int code, i, nodicts;
  277. X
  278. X    nmatched = 0;
  279. X    wordlistptr = wordlist;
  280. X    if ((code = soundex(word, 3)) == BAD_WORD)
  281. X        return;
  282. X    nodicts = 1;
  283. X    for (i = 0; fileptr[i] != (char *) NULL; i++) {
  284. X        if (strlen(fileptr[i]) == 0)
  285. X            continue;
  286. X        if (DBMINIT(fileptr[i], O_RDONLY) != -1) {
  287. X            proc(code);
  288. X            nodicts = 0;
  289. X        }
  290. X        DBMCLOSE();
  291. X    }
  292. X    if (nodicts) {
  293. X        fprintf(stderr, "sp: Can't open any dictionaries\n");
  294. X        exit(1);
  295. X    }
  296. X    if (vflag && !eflag && nmatched == 0)
  297. X        printf("%s: no match\n", word);
  298. X    else
  299. X        choose(word);
  300. X}
  301. X
  302. X/*
  303. X * Look the word up in the current dictionary
  304. X * and save all the matches
  305. X * Note that only three digits are of the Soundex code are stored
  306. X * in a dictionary
  307. X */
  308. Xproc(soundex)
  309. Xint soundex;
  310. X{
  311. X    register int c, len;
  312. X    datum dbm_key, dbm_content;
  313. X    key_t *key, keyvec[KEYSIZE];
  314. X    char *mk_word(), *p;
  315. X
  316. X    key = keyvec;
  317. X    dbm_key.dptr = (char *) key;
  318. X    dbm_key.dsize = KEYSIZE;
  319. X    c = 0;
  320. X    while (1) {
  321. X        mk_key(key, soundex, c);
  322. X        dbm_content = FETCH(dbm_key);
  323. X
  324. X        if (dbm_content.dptr == 0)
  325. X            break;
  326. X
  327. X        if (IS_DELETED(dbm_content)) {
  328. X            if (++c > MAXCOUNT) {
  329. X                fprintf(stderr, "sp: entry count overflow\n");
  330. X                exit(1);
  331. X            }
  332. X            continue;
  333. X        }
  334. X
  335. X        if (nmatched == MAXWORDS) {
  336. X            fprintf(stderr, "sp: Too many matches\n");
  337. X            exit(1);
  338. X        }
  339. X
  340. X        p = mk_word(dbm_content.dptr, dbm_content.dsize, soundex);
  341. X        len = strlen(p);
  342. X        if (wordlistptr + len >= &wordlist[WORDSPACE]) {
  343. X            fprintf(stderr, "sp: Out of space for words\n");
  344. X            exit(1);
  345. X        }
  346. X        strncpy(wordlistptr, p, len);
  347. X        wordlistptr[len] = '\0';
  348. X        wordptr[nmatched++] = wordlistptr;
  349. X        wordlistptr += len + 1;
  350. X        if (++c > MAXCOUNT) {
  351. X            fprintf(stderr, "sp: entry count overflow\n");
  352. X            exit(1);
  353. X        }
  354. X    }
  355. X}
  356. X
  357. X/*
  358. X * Select and print those words which we consider
  359. X * to have matched 'word'
  360. X */
  361. Xchoose(word)
  362. Xregister char *word;
  363. X{
  364. X    register int c, code, i, len, mcount, wordlen;
  365. X    register char *p;
  366. X    int compar();
  367. X
  368. X    code = soundex(word, 4);
  369. X    qsort(wordptr, nmatched, sizeof(char *), compar);
  370. X    c = range(word);
  371. X    wordlen = strlen(word);
  372. X    mcount = 0;
  373. X    for (i = 0; i < nmatched; i++) {
  374. X        p = wordptr[i];
  375. X        if (strmatch(word, p) == 0) {
  376. X            printf("X");
  377. X            if (eflag) {
  378. X                printf(" %s\n", word);
  379. X                return;
  380. X            }
  381. X        }
  382. X        else if (eflag)
  383. X            continue;
  384. X        else if (soundex(p, 4) == code)
  385. X            printf("!");
  386. X        else if (aflag &&
  387. X            (wordlen < (len = strlen(p)) - c || len > wordlen + c))
  388. X            printf(" ");
  389. X        else if (!cflag)
  390. X            printf("*");
  391. X        else
  392. X            continue;
  393. X        printf("%3d. %s\n", mcount + 1, p);
  394. X        mcount++;
  395. X    }
  396. X    if (vflag)
  397. X        printf("(%d total matches)\n", nmatched);
  398. X}
  399. X
  400. X/*
  401. X * Compute an 'n' digit Soundex code for 'word' 
  402. X * See mksp.c
  403. X */
  404. Xsoundex(word, n)
  405. Xregister char *word;
  406. Xint n;
  407. X{
  408. X    register int c, digit_part, previous_code, soundex_length;
  409. X    register char *p, *w;
  410. X    char wcopy[MAXWORDLEN + 2];
  411. X
  412. X    strcpy(wcopy, word);
  413. X    p = w = wcopy;
  414. X    while (*p != '\0') {
  415. X        if (isupper(*p))
  416. X            *p = tolower(*p);
  417. X        p++;
  418. X    }
  419. X    if (!isalpha(*w)) {
  420. X        fprintf(stderr, "sp: Improper word: %s\n", word);
  421. X        return(BAD_WORD);
  422. X    }
  423. X    digit_part = 0;
  424. X    soundex_length = 0;
  425. X    previous_code = soundex_code_map[*w - 'a'];
  426. X    for (p = w + 1; *p != '\0' && soundex_length < n; p++) {
  427. X        if (!isalpha(*p))
  428. X            continue;
  429. X        c = soundex_code_map[*p - 'a'];
  430. X        if (c == 0 || previous_code == c) {
  431. X            previous_code = c;
  432. X            continue;
  433. X        }
  434. X        digit_part = digit_part * 7 + c;
  435. X        previous_code = c;
  436. X        soundex_length++;
  437. X    }
  438. X    while (soundex_length++ < n)
  439. X        digit_part *= 7;
  440. X    return((digit_part << 5) + *w - 'a');
  441. X}
  442. X
  443. X/*
  444. X * Process a path string (environment variable SPPATH, DEFAULT_SPPATH, or an
  445. X * arg) by separating the pathnames into strings pointed to by elements
  446. X * of 'fileptr'
  447. X * End of list indicated by fileptr entry of NULL
  448. X *
  449. X * No attempt made to ignore duplicate pathnames
  450. X */
  451. Xmkfilelist(p)
  452. Xregister char *p;
  453. X{
  454. X    register int len;
  455. X    register char *path, *start;
  456. X    char *malloc();
  457. X
  458. X    while (*p != '\0' && dict_ptr < MAXDICT) {
  459. X        start = p;
  460. X        while (*p != ':' && *p != '\0')
  461. X            p++;
  462. X        if (start == p && *p == ':') {    /* colon with nothing else */
  463. X            p++;
  464. X            continue;
  465. X        }
  466. X        len = p - start;
  467. X        path = (char *) malloc((unsigned) (len + 1));
  468. X        if (path == (char *) NULL) {
  469. X            fprintf(stderr, "sp: Out of dictionary space\n");
  470. X            exit(1);
  471. X        }
  472. X        strncpy(path, start, len);
  473. X        path[len] = '\0';
  474. X        fileptr[dict_ptr++] = path;
  475. X    }
  476. X    fileptr[dict_ptr] = (char *) NULL;
  477. X}
  478. X
  479. Xcompar(p, q)
  480. Xchar **p, **q;
  481. X{
  482. X
  483. X    return(strmatch(*p, *q));
  484. X/*    return(strcmp(*p, *q)); */    /* use if you prefer case sensitive */
  485. X}
  486. X
  487. @//E*O*F sp.c//
  488. if test 9128 -ne "`wc -c <'sp.c'`"; then
  489.     echo shar: error transmitting "'sp.c'" '(should have been 9128 characters)'
  490. fi
  491. fi # end of overwriting check
  492. echo shar: extracting "'sp.h'" '(3553 characters)'
  493. if test -f 'sp.h' ; then 
  494.   echo shar: will not over-write existing file "'sp.h'"
  495. else
  496. sed 's/^X//' >sp.h <<'@//E*O*F sp.h//'
  497. X/* sp.h */
  498. X/* vi: set tabstop=4 : */
  499. X
  500. X/*
  501. X * A deleted dbm entry is denoted by a dsize of zero
  502. X */
  503. X#define IS_DELETED(C)        (C.dsize == 0)
  504. X
  505. X/*
  506. X * Because the soundex code (part of the key) includes the first character of
  507. X * the word, we don't need to store the first character again with the content.
  508. X * To do this we treat the first byte of the content stored in the dbm
  509. X * specially:  we rip off the two high order bits of the first byte of
  510. X * the content and therefore have to restrict the value of the second
  511. X * character of the word.  We use 'a' == 0, 'z' == 25, 'A' == 26, 'Z' == 51.
  512. X * See spchar_map[] (misc.c) for the mapping of codes 52 through 63.
  513. X * This behaviour is isolated in tospchar() and fromspchar().
  514. X * If spchar_map is changed you should change the man page too.
  515. X *
  516. X * The word can be reconstructed by extracting the first character of the word
  517. X * from the soundex code and then looking at the first byte of the content.
  518. X * If the UPPER_CHAR bit is on in the first byte of the content then the first
  519. X * character of the word should be upper case.
  520. X * The length of the content reflects the actual number of bytes stored in the
  521. X * dbm.  Words that have been deleted from the dbm are stored with a length of
  522. X * zero.  Because of this, words of length 1 are treated differently: they are
  523. X * stored with a length of 1 and with the SINGLE_CHAR bit set.  Words with
  524. X * original length > 1 will have (length - 1) bytes stored in the content.
  525. X * Clear?
  526. X */
  527. X#define IS_VALID(w)        (isalpha(*w) && (*(w+1) == '\0' || isalpha(*(w+1)) \
  528. X                                        || tospchar(*(w+1)) != '\0'))
  529. X#define UPPER_CHAR        0200    /* 1st char of word is upper case */
  530. X#define SINGLE_CHAR        0100    /* single char word */
  531. X#define MASK_CHAR        0077    /* mask out the indicator bits */
  532. X#define QUOTE_CHAR        0064    /* (52) code for single quote */
  533. X#define AMPER_CHAR        0065    /* (53) for ampersand */
  534. X#define PERIOD_CHAR        0066    /* (54) for period */
  535. X#define SPACE_CHAR        0067    /* (55) for blank */
  536. X
  537. X/*
  538. X * Map for first byte of dbm content (special characters)
  539. X * Terminated by a null entry
  540. X */
  541. Xstruct spchar_map {
  542. X    char spchar;
  543. X    char code;
  544. X};
  545. X
  546. X#define MAXDICT            10        /* Max number of dictionaries to use */
  547. X#define MAXWORDLEN        50        /* Max word length */
  548. X#define MAXWORDS        400        /* Max number of words in one sp query */
  549. X#define WORDSPACE        20480    /* Max space used words for one sp query */
  550. X
  551. X/*
  552. X * This is the default path used by sp to find dictionaries
  553. X * Adjust for local conditions
  554. X */
  555. X#define DEFAULT_SPPATH    "/usr/local/lib/sp.dict.1:/usr/local/lib/sp.dict.2"
  556. X
  557. X/*
  558. X * The following must be the maximum value containable in the count part of
  559. X * a key.
  560. X * It must be always be less than: (the maximum positive value that can be
  561. X * contained in an int) - 1
  562. X * This value imposes a limit on the number of words in a dictionary having the
  563. X * same soundex code.  For /usr/dict/words (~25K words), a count of 255 is
  564. X * sufficient.  Larger dictionaries will need more.  In any case you can
  565. X * always just make another dictionary and split up your words.
  566. X * You might want to adjust MAXWORDS and WORDSPACE (above) to reflect MAXCOUNT
  567. X * if you've got plenty of memory.
  568. X */
  569. X#define MAXCOUNT    1023                /* 2^10 - 1 */
  570. X
  571. X/*
  572. X * The key used by dbm looks like this:
  573. X *
  574. X *     <10 bits>    <5 bits>    <9 bits>
  575. X *    counter        first char    soundex
  576. X *
  577. X * A soundex value is treated as a base 7 number (maximum is 666, base 7).
  578. X */
  579. X#define KEYSIZE        3                    /* in bytes */
  580. Xtypedef unsigned char key_t;
  581. X
  582. X#define BAD_WORD    -1                    /* This must be an illegal Soundex */
  583. X#define NO_MATCH     0
  584. X#define MATCHED         1
  585. X
  586. Xextern char soundex_code_map[];
  587. X
  588. @//E*O*F sp.h//
  589. if test 3553 -ne "`wc -c <'sp.h'`"; then
  590.     echo shar: error transmitting "'sp.h'" '(should have been 3553 characters)'
  591. fi
  592. fi # end of overwriting check
  593. echo shar: extracting "'sp.ml'" '(1613 characters)'
  594. if test -f 'sp.ml' ; then 
  595.   echo shar: will not over-write existing file "'sp.ml'"
  596. else
  597. sed 's/^X//' >sp.ml <<'@//E*O*F sp.ml//'
  598. X; 
  599. X; Written by Donald Acton and Barry Brachman with help from Marc Majka
  600. X;  March 11/85
  601. X;
  602. X; Dept. of Computer Science
  603. X; University of British Columbia
  604. X; 
  605. X
  606. X(defun 
  607. X    (sp spword
  608. X      (setq spword (get-tty-string "Word: " ))
  609. X      (do-sp spword)
  610. X    )
  611. X)
  612. X
  613. X(defun                        ; bjb
  614. X    (sp-from-buffer spword
  615. X    (setq spword (get-next-word))
  616. X    (message (concat "Word: " spword))
  617. X    (sit-for 0)
  618. X    (do-sp spword)
  619. X    )
  620. X)
  621. X
  622. X(defun
  623. X    (do-sp curr found tmp
  624. X      (setq curr (current-buffer-name))
  625. X      (pop-to-buffer "sp")
  626. X      (setq needs-checkpointing 0)
  627. X      (erase-buffer)
  628. X      (set-mark)
  629. X      (filter-region (concat "sp " spword))
  630. X      (beginning-of-file)
  631. X      (setq found " *not found*")
  632. X      (setq tmp case-fold-search)
  633. X      (setq case-fold-search 1)
  634. X      (error-occurred (re-search-forward (concat "\. " spword "$"))
  635. X                       (beginning-of-line)
  636. X                       (line-to-top-of-window)
  637. X                       (setq found " *found*"))
  638. X      (setq case-fold-search tmp)
  639. X      (setq mode-line-format " %b - %m      %p")
  640. X      (setq mode-string (concat spword found))
  641. X      (pop-to-buffer curr)
  642. X      (novalue)))
  643. X
  644. X;
  645. X; Return the word the cursor is pointing at
  646. X; or the word immediately to the left of the
  647. X; cursor if it is between words
  648. X;
  649. X; April 15/85 - bjb
  650. X;
  651. X(defun
  652. X    (get-next-word original-dot rb spword
  653. X    (save-excursion
  654. X        (setq original-dot (dot))
  655. X        (backward-word) (forward-word) (setq rb (dot))
  656. X        (if (> original-dot rb)
  657. X        (progn (forward-word) (backward-word))
  658. X        (backward-word))
  659. X        (set-mark)
  660. X        (forward-word)
  661. X        (setq spword (region-to-string))
  662. X    )
  663. X    spword
  664. X   )
  665. X) 
  666. X
  667. @//E*O*F sp.ml//
  668. if test 1613 -ne "`wc -c <'sp.ml'`"; then
  669.     echo shar: error transmitting "'sp.ml'" '(should have been 1613 characters)'
  670. fi
  671. fi # end of overwriting check
  672. echo shar: "End of archive 2 (of 2)."
  673. cp /dev/null ark2isdone
  674. DONE=true
  675. for I in 1 2; do
  676.     if test ! -f ark${I}isdone; then
  677.         echo "You still need to run archive ${I}."
  678.         DONE=false
  679.     fi
  680. done
  681. case $DONE in
  682.     true)
  683.         echo "You have run both archives."
  684.         echo 'See the README'
  685.         ;;
  686. esac
  687. ##  End of shell archive.
  688. exit 0
  689.